package com.lonwin.mes2u8.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.lonwin.mes2u8.domain.mes.MesBatchCodeInfo;
import com.lonwin.mes2u8.domain.mes.MesMaterialOutQueryResult;
import com.lonwin.mes2u8.domain.u8.*;
import com.lonwin.mes2u8.service.BatchCodeService;
import com.lonwin.mes2u8.service.InventoryAppService;
import com.lonwin.mes2u8.service.MaterialOutAppService;
import com.lonwin.mes2u8.util.MyQueueUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.Queue;
import java.util.stream.Collectors;

/**
 * 材料出库单相关操作
 *
 * @author DELL
 * @Date 2023-12-18 11:07
 */
@Controller
@RequestMapping("/materialout")
@ResponseBody
@Slf4j
public class MaterialOutController {

    @Resource
    private MaterialOutAppService materialAppService;
    @Resource
    private BatchCodeService batchCodeService;

    @Resource
    private InventoryAppService inventoryAppService;

    @GetMapping("/add")
    // public String addMaterial(@RequestParam String start, @RequestParam String end) {
    public String addMaterial() {
        log.info("MaterialController addMaterial  start");
        // 从MES拉取批次列表
        List<MesBatchCodeInfo> mesBatchCodeInfoList = batchCodeService.queryMesBatchList();

        if (mesBatchCodeInfoList.isEmpty()) {
            log.info("MaterialController addMaterial result 1 : query 0 , add 0");
            return "";
        }

        List<String> batchCodeList = mesBatchCodeInfoList.stream().map(MesBatchCodeInfo::getBno)
                .filter(s -> !s.startsWith("22") && !s.startsWith("23")).collect(Collectors.toList());

        return addMaterial(batchCodeList);
    }

    /*
     * 1. MES中按批次号查询可以得到这个批次号下所有成品的出库单记录
     * 2. 需要将MES中获取到的信息先按成品编号分组，再统计每个分组中原材料的数量
     * 3. 分别使用产成品编号去U8中查询出库单
     * 4. 将U8中查询到的出库单信息也进行汇总，得到每个原材料的已经录入的数量
     * 5. 将MES中获取到的数量减去U8中现在的数量即为待入库的数量
     * 6. 将其转换为U8的导入参数
     * 7. 导入出库单，再进行下一个成品编码的查询，到第3步
     */
    public String addMaterial(List<String> batchCodeList) {
        Queue<DefineSyncResponse> failedResult = Lists.newLinkedList();
        Queue<DefineSyncResponse> checkQueue = Lists.newLinkedList();

        // 从U8中查找指定批次号的材料出库单
        for (int i = 0; i < batchCodeList.size(); i++) {
            String batchCode = batchCodeList.get(i);
            log.info("MaterialController addMaterial totle {} now{} : {}", batchCodeList.size(), i+1, batchCode);
            // 查找mes材料出库单
            List<MesMaterialOutQueryResult> mesMaterialOutInfo = materialAppService.getMesMaterialOutInfo(batchCode);

            // 将MES材料出库单按照 成品编号 进行分组, 每一项都包含了当前批次、成品编号、实际使用了的物料编号、数量
            List<U8MaterialOutHandlerResult> mesLastMaterialOutInfoList = materialAppService.handleMesMaterialOutQueryResultOfGroup(mesMaterialOutInfo);

            List<U8MaterialOutHandlerResult> u8LastMaterialOutInfoList = Lists.newArrayList();

            if (Objects.nonNull(mesLastMaterialOutInfoList) &&!mesLastMaterialOutInfoList.isEmpty()){
                for (U8MaterialOutHandlerResult mesLastMaterialOutInfo : mesLastMaterialOutInfoList) {
                    // 按 产品编号 查找U8相关材料出库单
                    // 对U8材料出库单查询详情并汇总为集合
                    List<U8MaterialOutBatchGetInfo> u8MaterialOutBatchGetInfos =
                            materialAppService.getU8MaterialOutListByMesBatchCode(mesLastMaterialOutInfo.getInventoryCode());


                    // U8材料出库单列表
                    List<U8MaterialOutQueryBody> existU8MaterialQueryBodyList = Lists.newArrayList();

                    if (Objects.nonNull(u8MaterialOutBatchGetInfos) && !u8MaterialOutBatchGetInfos.isEmpty()) {

                        for (U8MaterialOutBatchGetInfo u8MaterialOutBatchGetInfo : u8MaterialOutBatchGetInfos) {
                            U8MaterialOutQueryBody u8MaterialOutQueryBody = materialAppService.queryMaterailOutFromU8(u8MaterialOutBatchGetInfo.getCode());
                            if (Objects.nonNull(u8MaterialOutQueryBody)) {
                                existU8MaterialQueryBodyList.add(u8MaterialOutQueryBody);
                            }
                        }
                    }

                    List<U8MaterialOutHandlerResultInfo> infos = materialAppService.handlerU8MaterialExistSumInfo(existU8MaterialQueryBodyList);
                    U8MaterialOutHandlerResult u8MaterialOutHandlerResult = U8MaterialOutHandlerResult.builder()
                            .batchCode(batchCode).inventoryCode(mesLastMaterialOutInfo.getInventoryCode()).infoList(infos).build();
                    u8LastMaterialOutInfoList.add(u8MaterialOutHandlerResult);
                }
            }

            // 对MES材料出库单和U8材料出库单进行处理，生成待录入的结果
            log.info("MaterialController addMaterial {} : mesLastMaterialOutInfoList : {}", i, JSON.toJSONString(mesLastMaterialOutInfoList));
            log.info("MaterialController addMaterial {} : u8LastMaterialOutInfoList : {}", i, JSON.toJSONString(u8LastMaterialOutInfoList));
            List<U8MaterialOutHandlerResult> billHandlerResultList = handlerCanRecord(mesLastMaterialOutInfoList, u8LastMaterialOutInfoList);

            for (U8MaterialOutHandlerResult u8MaterialOutHandlerResult : billHandlerResultList) {

                // 将结果转换为U8材料出库单录入参数
                U8MaterialOutAddParam addParam = U8MaterialOutAddParam.buildU8MaterialOutAddParamByBillHandlerResult(u8MaterialOutHandlerResult);

                if (Objects.nonNull(addParam) && !addParam.getMaterialout().getEntry().isEmpty()) {
                    // 录入材料出库单
                    U8CommonSyncResponse u8CommonSyncResponse = materialAppService.addMaterialOutToU8(addParam);

                    DefineSyncResponse defineSyncResponse = DefineSyncResponse.buildSelfBySyncResponse(u8CommonSyncResponse, u8MaterialOutHandlerResult.getInventoryCode(), MyObjTypeEnum.MATERIAL_OUT);
                    checkQueue.add(defineSyncResponse);
                }
            }

        }
        Queue<DefineSyncResponse> checkedResult = MyQueueUtil.checkQueueSuccess(checkQueue);

        failedResult.addAll(checkedResult);

        if (!failedResult.isEmpty()) {
            log.error("MaterialOutController.addMaterial record failed : {}", failedResult.size());
            log.error("MaterialOutController.addMaterial record failed info:");
            failedResult.forEach(
                    res -> log.error("{} -- {}", res.getCode(), res.getMessage())
            );
        }

        return "";
    }

    private List<U8MaterialOutHandlerResult> handlerCanRecord(List<U8MaterialOutHandlerResult> mesLastMaterialOutInfoList, List<U8MaterialOutHandlerResult> u8LastMaterialOutInfoList) {
        List<U8MaterialOutHandlerResult> resultList = Lists.newArrayList();

        for (U8MaterialOutHandlerResult mesLastItem : mesLastMaterialOutInfoList) {

            // 筛选U8中与当前MES成品相同的记录
            U8MaterialOutHandlerResult u8SameToMes = u8LastMaterialOutInfoList.stream()
                    .filter(u8LastItem -> u8LastItem.getInventoryCode().equals(mesLastItem.getInventoryCode()))
                    .findFirst().orElse(null);

            if (Objects.isNull(u8SameToMes)) {
                // for (U8MaterialOutHandlerResultInfo info : mesLastItem.getInfoList()) {
                //     info.setIrate(info.getWeight().divide(info.getNumber(), 6, RoundingMode.HALF_UP));
                // }
                resultList.add(mesLastItem);
                continue;
            }

            U8MaterialOutHandlerResult result = U8MaterialOutHandlerResult.builder().batchCode(mesLastItem.getBatchCode()).inventoryCode(mesLastItem.getInventoryCode().replace("-", "")).build();
            List<U8MaterialOutHandlerResultInfo> infos = Lists.newArrayList();
            for (U8MaterialOutHandlerResultInfo mesInfo : mesLastItem.getInfoList()) {

                U8MaterialOutHandlerResultInfo u8SameInfo = u8SameToMes.getInfoList().stream()
                        .filter(u8Info -> u8Info.getMno().equals(mesInfo.getMno())).findFirst().orElse(null);

                if (Objects.isNull(u8SameInfo)) {
                    // for (U8MaterialOutHandlerResultInfo info : mesLastItem.getInfoList()) {
                    //     mesInfo.setIrate(mesInfo.getWeight().divide(mesInfo.getNumber(), 6, RoundingMode.HALF_UP));
                    // }
                    infos.add(mesInfo);
                    continue;
                }
                BigDecimal difWeightValue = mesInfo.getWeight().subtract(u8SameInfo.getWeight());
                BigDecimal difNumberValue = mesInfo.getNumber().subtract(u8SameInfo.getNumber());
                if (difWeightValue.compareTo(BigDecimal.ZERO) > 0) {
                    U8MaterialOutHandlerResultInfo info = U8MaterialOutHandlerResultInfo.builder()
                            .mno(mesInfo.getMno())
                            .mdes(mesInfo.getMdes())
                            .weight(difWeightValue)
                            .number(difNumberValue)
                            // .irate(difNumberValue.divide(difNumberValue, 6, RoundingMode.HALF_UP))
                            .build();
                    infos.add(info);
                }
            }
            result.setInfoList(infos);
            resultList.add(result);
        }

        return resultList;
    }

}
